قدرت React Suspense را با الگوی منبع برای بارگذاری بهینه داده ها در سراسر اجزا کاوش کنید. نحوه مدیریت و به اشتراک گذاری کارآمد منابع داده، بهبود عملکرد و تجربه کاربری را بیاموزید.
منبع React Suspense: مدیریت کارآمد بارگذاری داده های به اشتراک گذاشته شده
React Suspense یک مکانیزم قدرتمند است که در React 16.6 معرفی شده است که به شما امکان می دهد رندر کامپوننت را در حین انتظار برای عملیات ناهمزمان مانند واکشی داده ها "به حالت تعلیق" درآورید. این امر راه را برای روشی اعلانی تر و کارآمدتر برای مدیریت حالت های بارگذاری و بهبود تجربه کاربری باز می کند. در حالی که Suspense خود یک ویژگی عالی است، ترکیب آن با الگوی منبع می تواند مزایای عملکردی بیشتری را به ویژه هنگام کار با داده های به اشتراک گذاشته شده در بین چندین کامپوننت باز کند.
درک React Suspense
قبل از پرداختن به الگوی منبع، بیایید به سرعت اصول React Suspense را مرور کنیم:
- Suspense برای واکشی داده ها: Suspense به شما امکان می دهد رندر یک کامپوننت را تا زمانی که داده های مورد نیاز آن در دسترس باشد، متوقف کنید.
- مرزهای خطا: در کنار Suspense، مرزهای خطا به شما این امکان را می دهند که به طور ظریف با خطاها در طول فرآیند واکشی داده ها برخورد کنید و در صورت بروز خطا، یک رابط کاربری جایگزین ارائه دهید.
- کامپوننت های بارگذاری تنبل: Suspense بارگذاری تنبل کامپوننت ها را فعال می کند، و با بارگیری فقط کامپوننت ها در صورت نیاز، زمان بارگذاری اولیه صفحه را بهبود می بخشد.
ساختار اساسی استفاده از Suspense به این صورت است:
<Suspense fallback={<p>در حال بارگذاری...</p>}>
<MyComponent />
</Suspense>
در این مثال، MyComponent ممکن است داده ها را به صورت ناهمزمان واکشی کند. اگر داده ها بلافاصله در دسترس نباشند، ویژگی fallback، در این مورد، یک پیام بارگیری، نمایش داده می شود. پس از آماده شدن داده ها، MyComponent رندر می شود.
چالش: واکشی داده های اضافی
در برنامه های پیچیده، معمول است که چندین کامپوننت به یک داده یکسان متکی باشند. یک رویکرد ساده این است که هر کامپوننت به طور مستقل داده های مورد نیاز خود را واکشی کند. با این حال، این می تواند منجر به واکشی داده های اضافی، هدر دادن منابع شبکه و به طور بالقوه کند کردن برنامه شود.
سناریویی را در نظر بگیرید که در آن داشبوردی دارید که اطلاعات کاربر را نمایش می دهد، و هم بخش نمایه کاربر و هم فید فعالیت های اخیر به جزئیات کاربر نیاز دارند. اگر هر کامپوننت واکشی داده های خود را آغاز کند، اساساً دو درخواست یکسان برای یک اطلاعات ایجاد می کنید.
معرفی الگوی منبع
الگوی منبع با ایجاد یک مجموعه متمرکز از منابع داده، راه حلی برای این مشکل ارائه می دهد. به جای اینکه هر کامپوننت داده ها را به طور مستقل واکشی کند، از مجموعه به منبع مشترک درخواست دسترسی می کند. اگر منبع از قبل در دسترس باشد (یعنی داده ها از قبل واکشی شده باشند)، بلافاصله برگردانده می شود. اگر منبع هنوز در دسترس نباشد، مجموعه واکشی داده ها را آغاز می کند و پس از اتمام، آن را در اختیار تمام کامپوننت های درخواست کننده قرار می دهد.
این الگو چندین مزیت را ارائه می دهد:
- کاهش واکشی اضافی: تضمین می کند که داده ها فقط یک بار واکشی می شوند، حتی اگر چندین کامپوننت به آن نیاز داشته باشند.
- بهبود عملکرد: سربار شبکه را کاهش می دهد و عملکرد کلی برنامه را بهبود می بخشد.
- مدیریت متمرکز داده ها: یک منبع واحد از حقیقت را برای داده ها فراهم می کند و مدیریت و سازگاری داده ها را ساده می کند.
پیاده سازی یک منبع با React Suspense
در اینجا نحوه پیاده سازی یک الگوی منبع با استفاده از React Suspense آورده شده است:
- ایجاد یک کارخانه منبع: این تابع کارخانه مسئول ایجاد وعده واکشی داده ها و ارائه رابط لازم برای Suspense خواهد بود.
- پیاده سازی منبع: مجموعه منابع ایجاد شده را ذخیره می کند و چرخه عمر آنها را مدیریت می کند. همچنین اطمینان حاصل می کند که فقط یک واکشی برای هر منبع منحصر به فرد آغاز می شود.
- استفاده از منبع در کامپوننت ها: کامپوننت ها از مجموعه، منبع را درخواست می کنند و از
React.useبرای تعلیق رندر در حین انتظار برای داده ها استفاده می کنند.
1. ایجاد کارخانه منبع
کارخانه منبع یک تابع واکشی داده را به عنوان ورودی دریافت می کند و یک شی را برمی گرداند که می تواند با React.use استفاده شود. این شی به طور معمول یک روش read خواهد داشت که یا داده ها را برمی گرداند یا اگر داده ها هنوز در دسترس نباشند، یک وعده ایجاد می کند.
function createResource(fetchData) {
let status = 'pending';
let result;
let suspender = fetchData().then(
(r) => {
status = 'success';
result = r;
},
(e) => {
status = 'error';
result = e;
}
);
return {
read() {
if (status === 'pending') {
throw suspender;
} else if (status === 'error') {
throw result;
} else if (status === 'success') {
return result;
}
},
};
}
توضیح:
- تابع
createResourceیک تابعfetchDataرا به عنوان ورودی دریافت می کند. این تابع باید وعده ای را برگرداند که با داده ها حل می شود. - متغیر
statusوضعیت واکشی داده ها را ردیابی می کند:'pending'،'success'یا'error'. - متغیر
suspenderوعده برگشتی توسطfetchDataرا نگه می دارد. از روشthenبرای به روز رسانی متغیرهایstatusوresultهنگام حل یا رد وعده استفاده می شود. - روش
readکلید ادغام با Suspense است. اگرstatus'pending'باشد، وعدهsuspenderرا می اندازد و باعث می شود Suspense رندر را به حالت تعلیق درآورد. اگرstatus'error'باشد، خطا را می اندازد و به مرزهای خطا اجازه می دهد آن را بگیرند. اگرstatus'success'باشد، داده ها را برمی گرداند.
2. پیاده سازی منبع
منبع مسئول ذخیره و مدیریت منابع ایجاد شده خواهد بود. اطمینان حاصل می کند که فقط یک واکشی برای هر منبع منحصر به فرد آغاز می شود.
const resourcePool = {
cache: new Map(),
get(key, fetchData) {
if (!this.cache.has(key)) {
this.cache.set(key, createResource(fetchData));
}
return this.cache.get(key);
},
};
توضیح:
- شی
resourcePoolدارای یک ویژگیcacheاست که یکMapاست که منابع ایجاد شده را ذخیره می کند. - روش
getیکkeyو یک تابعfetchDataرا به عنوان ورودی دریافت می کند. ازkeyبرای شناسایی منحصر به فرد منبع استفاده می شود. - اگر منبع از قبل در حافظه پنهان نباشد، با استفاده از تابع
createResourceایجاد شده و به حافظه پنهان اضافه می شود. - روش
getسپس منبع را از حافظه پنهان برمی گرداند.
3. استفاده از منبع در کامپوننت ها
اکنون، می توانید از منبع در کامپوننت های React خود برای دسترسی به داده ها استفاده کنید. از قلاب React.use برای دسترسی به داده ها از منبع استفاده کنید. این کار به طور خودکار کامپوننت را در صورت عدم وجود داده ها به حالت تعلیق در می آورد.
import React from 'react';
function MyComponent({ userId }) {
const userResource = resourcePool.get(userId, () => fetchUser(userId));
const user = React.use(userResource).user;
return (
<div>
<h2>نمایه کاربر</h2>
<p>نام: {user.name}</p>
<p>ایمیل: {user.email}</p>
</div>
);
}
function fetchUser(userId) {
return fetch(`https://api.example.com/users/${userId}`).then((response) =>
response.json()
).then(data => ({user: data}));
}
export default MyComponent;
توضیح:
- کامپوننت
MyComponentیک ویژگیuserIdرا به عنوان ورودی دریافت می کند. - روش
resourcePool.getبرای دریافت منبع کاربر از مجموعه استفاده می شود.keyuserIdاست و تابعfetchDatafetchUserاست. - از قلاب
React.useبرای دسترسی به داده ها ازuserResourceاستفاده می شود. این کار در صورت عدم وجود داده ها، کامپوننت را به حالت تعلیق در می آورد. - سپس کامپوننت نام و ایمیل کاربر را رندر می کند.
در نهایت، کامپوننت خود را با <Suspense> بپیچید تا حالت بارگذاری را مدیریت کنید:
<Suspense fallback={<p>در حال بارگذاری نمایه کاربر...</p>}>
<MyComponent userId={123} />
</Suspense>
ملاحظات پیشرفته
بی اعتبار کردن حافظه پنهان
در برنامه های دنیای واقعی، داده ها می توانند تغییر کنند. شما به مکانیزمی برای بی اعتبار کردن حافظه پنهان هنگام به روز رسانی داده ها نیاز دارید. این می تواند شامل حذف منبع از مجموعه یا به روز رسانی داده ها در منبع باشد.
resourcePool.invalidate = (key) => {
resourcePool.cache.delete(key);
};
مدیریت خطا
در حالی که Suspense به شما امکان می دهد حالت های بارگذاری را به طور ظریف مدیریت کنید، به همان اندازه مهم است که خطاها را مدیریت کنید. کامپوننت های خود را با مرزهای خطا بپیچید تا هر گونه خطایی را که در طول واکشی یا رندر داده ها رخ می دهد، دریافت کنید.
import React, { Component } from 'react';
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.error(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>مشکلی پیش آمد.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
<ErrorBoundary>
<Suspense fallback={<p>در حال بارگذاری نمایه کاربر...</p>}>
<MyComponent userId={123} />
</Suspense>
</ErrorBoundary>
سازگاری SSR
هنگام استفاده از Suspense با رندرینگ سمت سرور (SSR)، باید اطمینان حاصل کنید که داده ها قبل از رندر کامپوننت در سرور واکشی می شوند. این کار را می توان با استفاده از کتابخانه هایی مانند react-ssr-prepass یا با واکشی دستی داده ها و انتقال آن به کامپوننت به عنوان ویژگی ها انجام داد.
متن سراسری و بین المللی سازی
در برنامه های جهانی، در نظر بگیرید که منبع چگونه با متن های سراسری مانند تنظیمات زبان یا تنظیمات برگزیده کاربر تعامل دارد. اطمینان حاصل کنید که داده های واکشی شده به طور مناسب محلی سازی شده اند. به عنوان مثال، اگر جزئیات محصول را واکشی می کنید، اطمینان حاصل کنید که توضیحات و قیمت ها به زبان و ارز دلخواه کاربر نمایش داده می شوند.
مثال:
import { useContext } from 'react';
import { LocaleContext } from './LocaleContext';
function ProductComponent({ productId }) {
const { locale, currency } = useContext(LocaleContext);
const productResource = resourcePool.get(`${productId}-${locale}-${currency}`, () =>
fetchProduct(productId, locale, currency)
);
const product = React.use(productResource);
return (
<div>
<h2>{product.name}</h2>
<p>{product.description}</p>
<p>قیمت: {product.price} {currency}</p>
</div>
);
}
async function fetchProduct(productId, locale, currency) {
// Simulate fetching localized product data
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate network delay
const products = {
'123-en-USD': { name: 'Awesome Product', description: 'A fantastic product!', price: 99.99 },
'123-fr-EUR': { name: 'Produit Génial', description: 'Un produit fantastique !', price: 89.99 },
};
const key = `${productId}-${locale}-${currency}`;
if (products[key]) {
return products[key];
} else {
// Fallback to English USD
return products['123-en-USD'];
}
}
در این مثال، LocaleContext زبان و ارز دلخواه کاربر را ارائه می دهد. کلید منبع با استفاده از productId، locale و currency ساخته می شود و اطمینان حاصل می کند که داده های محلی شده صحیح واکشی می شوند. تابع fetchProduct واکشی داده های محصول محلی شده را بر اساس محل و ارز ارائه شده شبیه سازی می کند. اگر یک نسخه محلی شده در دسترس نباشد، به یک پیش فرض (انگلیسی/دلار آمریکا در این مورد) باز می گردد.
مزایا و معایب
مزایا
- بهبود عملکرد: واکشی داده های اضافی را کاهش می دهد و عملکرد کلی برنامه را بهبود می بخشد.
- مدیریت متمرکز داده ها: یک منبع واحد از حقیقت را برای داده ها فراهم می کند و مدیریت و سازگاری داده ها را ساده می کند.
- حالت های بارگذاری اعلانی: Suspense به شما امکان می دهد حالت های بارگذاری را به روشی اعلانی و قابل ترکیب مدیریت کنید.
- تجربه کاربری بهبود یافته: با جلوگیری از حالت های بارگذاری ناخوشایند، یک تجربه کاربری روان تر و پاسخگوتر را ارائه می دهد.
معایب
- پیچیدگی: پیاده سازی یک منبع می تواند پیچیدگی را به برنامه شما اضافه کند.
- مدیریت حافظه پنهان: نیاز به مدیریت دقیق حافظه پنهان برای اطمینان از سازگاری داده ها دارد.
- احتمال ذخیره سازی بیش از حد: اگر به درستی مدیریت نشود، حافظه پنهان می تواند قدیمی شود و منجر به نمایش داده های قدیمی شود.
جایگزین هایی برای منبع
در حالی که الگوی منبع راه حل خوبی را ارائه می دهد، بسته به نیازهای خاص شما، جایگزین های دیگری نیز برای در نظر گرفتن وجود دارد:
- Context API: از React's Context API برای به اشتراک گذاری داده ها بین کامپوننت ها استفاده کنید. این یک رویکرد ساده تر از منبع است، اما همان سطح کنترل را بر واکشی داده ها ارائه نمی دهد.
- Redux یا سایر کتابخانه های مدیریت وضعیت: از یک کتابخانه مدیریت وضعیت مانند Redux برای مدیریت داده ها در یک فروشگاه متمرکز استفاده کنید. این یک گزینه خوب برای برنامه های پیچیده با داده های زیاد است.
- مشتری GraphQL (به عنوان مثال، Apollo Client، Relay): مشتریان GraphQL مکانیزم های حافظه پنهان و واکشی داده های داخلی را ارائه می دهند که می تواند به جلوگیری از واکشی اضافی کمک کند.
نتیجه
الگوی منبع React Suspense یک تکنیک قدرتمند برای بهینه سازی بارگذاری داده ها در برنامه های React است. با به اشتراک گذاری منابع داده در بین کامپوننت ها و استفاده از Suspense برای حالت های بارگذاری اعلانی، می توانید به طور قابل توجهی عملکرد را بهبود بخشید و تجربه کاربری را افزایش دهید. در حالی که مقداری پیچیدگی را اضافه می کند، مزایا اغلب بیشتر از هزینه ها هستند، به ویژه در برنامه های پیچیده با داده های به اشتراک گذاشته شده زیاد.
به یاد داشته باشید که هنگام پیاده سازی یک منبع، بی اعتبار کردن حافظه پنهان، مدیریت خطا و سازگاری SSR را به دقت در نظر بگیرید. همچنین، رویکردهای جایگزین مانند Context API یا کتابخانه های مدیریت وضعیت را برای تعیین بهترین راه حل برای نیازهای خاص خود بررسی کنید.
با درک و به کارگیری اصول React Suspense و الگوی منبع، می توانید برنامه های وب کارآمدتر، پاسخگوتر و کاربرپسندتر برای مخاطبان جهانی بسازید.